#include "SOCK_Acceptor.h"
#include <winsock.h>
#include "IReactor.h"
#include <iostream>

#include "ConcreteReactor.h"
#include "RefinedReactor.h"

#include "ConcreteAcceptor.h"
#include "ConcreteConnector.h"
#include "PatientValueEventServer.h"
#include "PatientValueEventClient.h"

#include "INET_Addr.h"
#include "SOCK_Stream.h"
#include "SOCK_Acceptor.h"
#include "File.h"

#define _port 3490
#define _localAddress "127.0.0.1"

using namespace std;

void startAsServer();
void startAsClient();

void main()
{
	setlocale(LC_ALL, "");
	char mode[2] = {};

	while(true)
	{
		cout << "Press S for server or C for client: ";
		cin >> mode;

		if(*mode == 's' || *mode == 'S')
			startAsServer();

		else if(*mode == 'c' || *mode == 'C')
			startAsClient();

		else
			cout << "Undefined command... Try again" << endl << endl;
	}
}

void startAsClient()
{
	// prepare data
	char ipaddress[50] = "";
	const char localHost[10] = _localAddress;
	char* selectedAddress;
	bool connected = false;

	while(!connected)
	{
		selectedAddress = ipaddress;
		cout << "Write IP address (type L to use local host): " << endl;
		cin >> selectedAddress;

		if(*selectedAddress == 'l' || *selectedAddress == 'L')
			selectedAddress = (char*)localHost;

		timeval time;
		time.tv_sec = 3;
		time.tv_usec = 0;

		// Init connecion
		ConcreteReactor conReactor = ConcreteReactor();
		RefinedReactor refinedReactor = RefinedReactor(&conReactor);
		PatientValueEventClient client = PatientValueEventClient(&refinedReactor);

		INET_Addr addressLog = INET_Addr(_port, selectedAddress);
		ConcreteConnector connect = ConcreteConnector(&refinedReactor);
	
		connect.connect(&client,&addressLog);

		//TO CHECK: Remove event if not connected
		connected = refinedReactor.handle_events(&time);

		if(connected)
		{
			cout << "Connected!" << endl << endl;

			while(true)
			{
				refinedReactor.handle_events(&time);
			}
		}
		else
		{
			cout << "Could not connect. Resetting..." << endl << endl;
		}
	}
}

void startAsServer()
{
	ConcreteReactor conReactor = ConcreteReactor();
	RefinedReactor refinedReactor = RefinedReactor(&conReactor);
	INET_Addr addressLog = INET_Addr(_port, INADDR_ANY);
	File file = File(NULL);

	timeval time;
	time.tv_sec = 0;
	time.tv_usec = 500000;

	ConcreteAcceptor accept = ConcreteAcceptor(&refinedReactor,addressLog, &file);
	refinedReactor.handle_events(&time);

	cout << "Waiting for connection requests.";

	while(true)
	{
		refinedReactor.handle_events(&time);
		cout << ".";
	}
}